#include "Guerrier.h"

//#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost::assign;

const unsigned int Guerrier::nbr_comp = 15;

const unsigned int Guerrier::nbr_restric = 7;

const vector<ListComp> Guerrier::Comp = list_of
  (ListComp("Commandement"                  ,  5))
  (ListComp("Construction d'engins de siège",  5))
  (ListComp("Déplacement silencieux"        , 10))
  (ListComp("Dés de vie à 1d12"             , 10))
  (ListComp("Esquive"                       , 10))
  (ListComp("Machines de guerre"            ,  5))
  (ListComp("Rapidité"                      ,  5))
  (ListComp("Résistance à la magie"         , 10))
  (ListComp("Résistance au poison"          ,  5))
  (ListComp("Résistance aux sorts"          ,  5))
  (ListComp("Spécialisation"                ,  5))
  (ListComp("Spécialisations multiples"     , 10))
  (ListComp("Suivants (niv 9)"              ,  5))
  (ListComp("Suivants"                      , 10))
  (ListComp("Supervision"                   ,  5));

const vector<ListComp> Guerrier::Restric = list_of
  (ListComp("Limitation d'armes"                          ,  5))
  (ListComp("Limitation à la maille"                      ,  5))
  (ListComp("Limitation au cuir clouté"                   , 10))
  (ListComp("Sans armure"                                 , 15))
  (ListComp("Lim : potions, huiles et parchemins"         ,  5))
  (ListComp("Lim : anneau, de bâton, bâtonnet et baguette",  5))
  (ListComp("Lim : armes et armures magiques"             ,  5));


const vector< Prerequis > Guerrier::Limites = list_of
  (Prerequis(0, 9));

const set< string > Guerrier::RacesAdmises = list_of
  ( "Humain" ) ( "Demi-Elfe" ) ( "Demi-Ogre" ) ( "Demi-Orque" )
  ( "Elfe" ) ( "Gnome" ) ( "Hobbit" ) ( "Nain" );

/** Constructeur usuel.
 * Permet la construction d'un guerrier de A à Z, càd on détermine ici
 * les restrictions, puis les compétences.
 * @param xp le nombre de pts d'expérience du Guerrier.
 * @param trait les traits du Guerrier, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param PP nombre de points de personnage (PP) à disposition pour la
 * céation du Guerrier.
 * @param race nom de la race du personnage.
 */
Guerrier::Guerrier(unsigned int xp, const vector< unsigned int >& trait,
		   unsigned int& PP, const string& race)
  : Classe(xp, trait, Combattants, race)
{
  Type_classe = "Guerrier";
  PP += 15;

  NombreTotalCompetences  = nbr_comp;
  NombreTotalRestrictions = nbr_restric;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< ListComp > >( Comp );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  blank() << setfill('*') << setw(56) << '*' << endreq;
  blank() << "Création d'un guerrier" << endl << endreq;

  construitClasse( PP );

//   unsigned int nbr(0);
 
//   for (unsigned int i(0); i < nbr_restric; i++)
//     {
//       if (Restric[i].Cout != 0)
// 	blank() << i+1 << ' ' << (Restric[i].Comp)
// 		    << " (" << Restric[i].Cout << " pp)" << endreq;
//       else
// 	blank() << i+1 << ' ' << (Restric[i].Comp)
// 		    << " cout variable" << endreq;	
//     }
//   blank() << nbr_restric + 1 << " Aucune" << endreq;

//   bool test(true), deja_pris(false), encore(false);
//   unsigned int save_PP(PP);

//   do
//     {
//       do
// 	{
// 	  nbr = demanderUnsignedBorne("Choisir les restrictions ", 1,
// 					nbr_restric + 1);
// 	  if (nbr != nbr_restric + 1)
// 	    {
// 	      if (Restric[nbr-1].Cout == 0)
// 		{
// 		  deja_pris = safePushBack(&Comp_classe, 14+nbr);
// 		  if (deja_pris)
// 		    warning() << "Déjà sélectionné" << endreq;
// 		  else
// 		    {
// 		      Comp_classe.push_back(14+nbr);
// 		      unsigned int pps;
// 		      pps =  demanderUnsigned("Entrez les PP obtenus : ");
// 		      PP += pps;
// 		      blank() << "Restriction choisie : "
// 				  << (Restric[nbr-1].Comp) << endreq;
// 		    }
// 		}
// 	      else
// 		{
// 		  deja_pris = safePushBack(&Comp_classe, 14+nbr);
// 		  if (deja_pris)
// 		    warning() << "Déjà sélectionné" << endreq;
// 		  else
// 		    {
// 		      Comp_classe.push_back(14+nbr);
// 		      PP += Restric[nbr-1].Cout;
// 		      blank() << "Restriction choisie : "
// 				  << (Restric[nbr-1].Comp) << endreq;
// 		    }
// 		}
// 	    }
// 	  else
// 	    test = false;
// 	}
//       while(test);

//       afficheCompetences();
//       blank() << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
//       nbr = demanderUnsignedBorne("Choix ", 1, 2);
//       if (nbr == 2)
// 	{
// 	  PP = save_PP;
// 	  Comp_classe.clear();
// 	  test = true;
// 	  encore = true;
// 	  blank() << endreq;
// 	}
//       else
// 	encore = false;
//     }
//   while(encore);

//   test = true;

//   blank() << "Tu as " << PP << " pp à dépenser" << endreq;
//   save_PP = PP;

//   for (unsigned int i(0); i < nbr_comp; i++)
//     {
//       if (Comp[i].Cout != 0)
// 	blank() << i+1 << ' ' << (Comp[i].Comp)
// 		    << " (" << Comp[i].Cout << " pp)" << endreq;
//       else
// 	blank() << i+1 << ' ' << (Comp[i].Comp)
// 		    << " (cout variable)" << endreq;	
//     }
//   blank() << nbr_comp + 1 << " Aucune" << endreq;
//   blank() << "Choisir les compétences de classe" << endreq;

//   do
//     {
//       do
// 	{
// 	  nbr = demanderUnsignedBorne("("+ecrireString(PP)+" restants) ", 1,
// 					nbr_comp + 1);
// 	  if (nbr != nbr_comp + 1)
// 	    {
// 	      if (PP >= Comp[nbr-1].Cout)
// 		{
// 		  deja_pris = safePushBack(&Comp_classe, nbr - 1);
// 		  if (deja_pris)
// 		    warning() << "Déjà sélectionné" << endreq;
// 		  else
// 		    {
// 		      Comp_classe.push_back(nbr - 1);
// 		      PP -= Comp[nbr-1].Cout;
// 		      blank() << "Compétence choisie : "
// 				  << (Comp[nbr-1].Comp) << endreq;
// 		    }
// 		}
// 	      else
// 		blank() << "Pas assez de pp" << endreq;
// 	    }
// 	  else
// 	    test = false;
// 	}
//       while(test);

//       afficheCompetences();
//       blank() << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
//       nbr = demanderUnsignedBorne("Choix ", 1, 2);
//       if (nbr == 2)
// 	{
// 	  PP = save_PP;
// 	  while(Comp_classe.back() < nbr_comp)
// 	    Comp_classe.pop_back();
// 	  test = true;
// 	  encore = true;
// 	  blank() << endreq;
// 	}
//       else
// 	encore = false;
//     }
//   while(encore);

  blank() << endl << setfill('*') << setw(56) << '*' << endreq;
  calculNiveau();
}

/** Constructeur simplifié.
 * Permet de construire un Guerrier lors de la lecture d'un ficier xml.
 * @param xp le nombre de pts d'expérience du Guerrier.
 * @param trait les traits du Guerrier, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param race nom de la race du personnage.
 */
Guerrier::Guerrier(unsigned int xp, const vector< unsigned int >& trait,
		   const string& race)
  : Classe(xp, trait, Combattants, race)
{
  Type_classe = "Guerrier";

  NombreTotalCompetences  = nbr_comp;
  NombreTotalRestrictions = nbr_restric;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< ListComp > >( Comp );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  calculNiveau();
}

/** Constructeur pour le mode graphique.
 * Permet de construire une instance de Guerrier avec le contenu
 * minimal, le nombre de points d'expériences et les capacités étant
 * déterminées après la déclaration.
 *
 * @param trait les traits du Guerrier, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param UI contrôle, est présent pour des raisons historiques.
 * @param race nom de la race du personnage.
 */
Guerrier::Guerrier(const vector< unsigned int >& trait, const bool& UI,
		   const string& race)
  : Classe(0, trait, Combattants, race)
{
  if (!UI)
    {
      error() << "Création du personnage impossible" << endreq;
      exit(1);
    }

  Type_classe = "Guerrier";

  NombreTotalCompetences  = nbr_comp;
  NombreTotalRestrictions = nbr_restric;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< ListComp > >( Comp );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  calculNiveau();
}

/**
 * Constructeur de "copie", destiné à être utilisé depuis MetaClasse.
 *
 * @param ptr pointeur sur un objet de type Classe (MetaClasse en
 * fait).
 */
Guerrier::Guerrier(Classe *ptr)
  : Classe( *ptr )
{
  Type_classe = "Guerrier";

  NombreTotalCompetences  = nbr_comp;
  NombreTotalRestrictions = nbr_restric;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< ListComp > >( Comp );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  calculNiveau();
}

/** 
 * Destructeur, ne fait rien.
 */
Guerrier::~Guerrier()
{}

void Guerrier::calculNiveau()
{
  if (XP < 125000)
    {
      unsigned int i;
      for (i = 0; i < 6; i++)
	{
	  if (XP < (unsigned int) 2000 * puissance(2, i))
	    break;
	}
      Niveau = i + 1;
    }
  else if (XP < 250000)
    Niveau = 8;
  else
      Niveau = (XP - 250000) / 250000 + 9;
}

// void Guerrier::afficher_stats(ostream& os)
// {
//   os << "Guerrier" << endreq;
//   for (unsigned int i(0); i<6; i++)
//     os << Caracteristiques[i] << ' ' << Traits[i] << endreq;
//   for (unsigned int i(0); i<Comp_classe.size(); i++)
//     {
//       if(Comp_classe[i] >= 15)
// 	os << (Restric[Comp_classe[i]-15].Comp) << endreq;
//       else
// 	os << (Comp[Comp_classe[i]].Comp) << endreq;
//     }
// }

// void Guerrier::appliquerModif(const string& type)
// {}

// void Guerrier::augmenterTalents(const unsigned int& bonus, const bool& lvl_up)
// {}

void Guerrier::getJS(unsigned int *tab) const
{
  Debug::empileNiveau( &fonction );
  //DebugLevelType etat_precedent(dout.getLevel());
  //dout.setLevel(fonction);
  *(tab + 0) = 14; // Paralysie, Poison ou Mort magique
  *(tab + 1) = 16; // Bâton, batonnet baguette
  *(tab + 2) = 15; // Pétrification ou Métamorphose
  *(tab + 3) = 17; // Souffles
  *(tab + 4) = 17; // Sorts

  debug() << "Niveau = " << Niveau << endreq;
  
  unsigned int cat;
  if (Niveau <= 2)
    cat = 0;
  else  if (Niveau <= 4)
    cat = 1;
  else  if (Niveau <= 6)
    cat = 3;
  else  if (Niveau <= 8)
    cat = 4;
  else  if (Niveau <= 10)
    cat = 6;
  else  if (Niveau <= 12)
    cat = 7;
  else  if (Niveau <= 14)
    cat = 9;
  else  if (Niveau <= 16)
    cat = 10;
  else
    cat = 11;

  *(tab + 0) -= cat;
  *(tab + 1) -= cat;
  *(tab + 2) -= cat;
  *(tab + 3) -= cat;
  *(tab + 4) -= cat;

  if (cat == 3)
    *(tab + 3) = 13;
  else if (cat == 4)
    *(tab + 3) = 12;
  else if (cat == 4)
    *(tab + 3)  = 9;
  else if (cat == 6)
    *(tab + 3) = 8;
  else if (cat == 7)
    *(tab + 3) = 5;
  else if (cat >= 10)
    *(tab + 3) = 4;
  Debug::depileNiveau();//dout.setLevel(etat_precedent);
}

// string Guerrier::getCompetence(const unsigned int& i) const
// {
//   Debug::empileNiveau( &elementaire );
//   //DebugLevelType etat_precedent(dout.getLevel());
//   //dout.setLevel(elementaire);
//   if (getComp(i) < nbr_comp)
//     {
//       debug() << "comp " << getComp(i) << " => comp" << endreq;
//       Debug::depileNiveau();//dout.setLevel(etat_precedent);
//       return (Comp[getComp(i)].Comp);
//     }
//   else
//     {
//       debug() << "comp " << getComp(i) << " => res" << endreq;
//       Debug::depileNiveau();//dout.setLevel(etat_precedent);
//       return (Restric[getComp(i)-nbr_comp].Comp);
//     }
// }

unsigned int Guerrier::calculeTAc0() const
{
  return 21 - Niveau;
}

void Guerrier::calculNivMag()
{
  Niveau_mag = 0;
}

// void Guerrier::ecrireSorts(const string& nom_fichier, const bool& ecrase) const
// {
//   Debug::empileNiveau( &fonction );
//   //DebugLevelType etat_precedent(dout.getLevel());
//   //dout.setLevel(fonction);
//   debug() << "Rien à faire" << endl << flush;
//   ofstream sortie;
//   if (ecrase)
//     sortie.open(nom_fichier.c_str());
//   else
//     sortie.open(nom_fichier.c_str(), ios::app);
//   sortie << "%"  << getClasse() << endl << "% rien à dire" << endl;
//   sortie.close();
//   Debug::depileNiveau();//dout.setLevel(etat_precedent);
// }

// void Guerrier::nbrSort(unsigned int sorts[], const unsigned int& taille) const
// {
//   Debug::empileNiveau( &fonction );
//   //DebugLevelType etat_precedent(dout.getLevel());
//   //dout.setLevel(fonction);
//   debug() << "Rien à faire, mais le faire proprement" << endreq;
//   Debug::depileNiveau();//dout.setLevel(etat_precedent);
// }

/**
 * Permet de gérer les compétences martiales, càd lesquelles sont
 * accessibles à quel coût.
 *
 * Pour un Guerrier, comme pour tous les combattants, le coût est de 2
 * pour n'importe quelle arme. De plus, il peut acquérir un groupe
 * restreint pour 4 pp et un groupe large pour 6 pp.
*/
void Guerrier::getPrixAcces(map<string, unsigned int>*& Map) const
{
  Debug::empileNiveau( & fonction );
  //DebugLevelType etat_precedent(dout.getLevel());
  //dout.setLevel(fonction);
  func() << "Guerrier::getPrixAcces -> début" << endreq;

  map<string, unsigned int>::const_iterator mapIt, mapBegin(Map -> begin()),
    mapEnd(Map -> end());

  for (mapIt = mapBegin; mapIt != mapEnd; mapIt++)
    {
      lfunc() << mapIt -> first << endreq;
    }
  Map -> operator[]("Guerrier") = 2;
  
  func() << "Guerrier::getPrixAcces -> fin" << endreq;
  Debug::depileNiveau();//dout.setLevel(etat_precedent);
}
